﻿using EasySchedule.DataModel;
using EasySchedule.ServiceAgent;
using Microsoft.Practices.Prism.StoreApps;
using Microsoft.Practices.Prism.StoreApps.Interfaces;
using System;
using System.Collections.ObjectModel;
using System.Windows.Input;
using Windows.Storage;

namespace EasySchedule.ViewModels
{
    public class MainViewModel : ViewModelBase
    {
        private string authorizationUrl;
        private ApplicationDataContainer localSettings;
        private ICommand logInProxyCommand;
        private ServiceManager manager;
        private string name;
        private INavigationService navigationService;
        private ObservableCollection<PollViewModel> polls;

        private ServiceGateway<User> serviceGateway;
        private ISessionStateService session;
        private User user;
        private string userFileName = "user.xml";

        public MainViewModel(ISessionStateService session, INavigationService navigationService)
        {
            this.PropertyChanged += OnPropertyChanged;
            this.navigationService = navigationService;
            this.session = session;
            localSettings = ApplicationData.Current.LocalSettings;
            localSettings.CreateContainer(serviceDataKey, ApplicationDataCreateDisposition.Always);

            var access_token = localSettings.Containers[settingsKey].Values["access_token"] as string;
            var access_token_secret = localSettings.Containers[settingsKey].Values["access_token_secret"] as string;

            this.LogInCommand = new DelegateCommand(ExecuteLogIn, CanExecuteLogIn);
            this.RefreshUserCommand = new DelegateCommand(ExecuteRefreshUser, CanExecuteRefreshUser);
            this.OpenPollCommand = new DelegateCommand<object>(ExecuteOpenPoll, CanExecuteOpenPoll);

            if (string.IsNullOrEmpty(access_token) || string.IsNullOrEmpty(access_token_secret))
            {
                this.manager = new ServiceManager();
            }
            else
            {
                this.manager = new ServiceManager(access_token, access_token_secret);
                this.serviceGateway = new ServiceGateway<User>(this.manager);
                LoadUser();
            }
        }

        public event EventHandler LoggedIn;

        public event EventHandler UserLoaded;

        public string AuthorizationUrl
        {
            get { return this.authorizationUrl; }
            set { SetProperty(ref this.authorizationUrl, value); }
        }

        [RestorableState]
        public User CurrentUser
        {
            get { return this.user; }
            set { SetProperty(ref this.user, value); }
        }

        public ICommand LogInCommand { get; private set; }

        public ICommand LogInProxyCommand
        {
            get { return this.logInProxyCommand; }
            set
            {
                SetProperty(ref this.logInProxyCommand, value);
            }
        }

        [RestorableState]
        public string Name
        {
            get { return this.name; }
            set { SetProperty(ref this.name, value); }
        }

        public ICommand OpenPollCommand { get; private set; }

        public ObservableCollection<PollViewModel> Polls
        {
            get { return this.polls; }
            set { SetProperty(ref this.polls, value); }
        }

        public ICommand RefreshUserCommand { get; private set; }

        private bool CanExecuteLogIn()
        {
            var access_token = localSettings.Containers[settingsKey].Values["access_token"] as string;
            var access_token_secret = localSettings.Containers[settingsKey].Values["access_token_secret"] as string;
            if (this.LogInProxyCommand == null) return false;
            return this.LogInProxyCommand.CanExecute(null) && string.IsNullOrEmpty(access_token) && string.IsNullOrEmpty(access_token_secret);
        }

        private bool CanExecuteOpenPoll(object parameter)
        {
            PollViewModel poll = parameter as PollViewModel;
            if (poll == null) return false;
            return true;
        }

        private bool CanExecuteRefreshUser()
        {
            var access_token = localSettings.Containers[settingsKey].Values["access_token"] as string;
            var access_token_secret = localSettings.Containers[settingsKey].Values["access_token_secret"] as string;

            if (string.IsNullOrEmpty(access_token) || string.IsNullOrEmpty(access_token_secret))
                return false;
            //TODO: check if there is a connections and i
            return true;
        }

        private async void ExecuteLogIn()
        {
            var response = await manager.AcquireRequestToken();

            this.AuthorizationUrl = OAuthConstants.URL_AUTHORIZE + "?oauth_token=" + manager.Token;

            Action<Uri> OnAuthorized = async (responseUri) =>
            {
                if (responseUri == null) return;
                String pin = null;
                var query = responseUri.Query.Replace("?", "");
                String[] keyValPairs = query.Split('&');

                for (int i = 0; i < keyValPairs.Length; i++)
                {
                    String[] splits = keyValPairs[i].Split('=');
                    switch (splits[0])
                    {
                        case "oauth_verifier":
                            pin = splits[1];
                            break;
                    }
                }
                if (string.IsNullOrEmpty(pin)) return;
                var accessResponse = await this.manager.AcquireAccessToken(OAuthConstants.URL_ACCESS_TOKEN, "GET", pin);

                localSettings.Containers[settingsKey].Values["access_token"] = ((IOAuthSettings)this.manager).AccessToken;
                localSettings.Containers[settingsKey].Values["access_token_secret"] = ((IOAuthSettings)this.manager).AccessSecret;
                if (this.RefreshUserCommand.CanExecute(null)) this.RefreshUserCommand.Execute(null);
                if (this.LoggedIn != null) this.LoggedIn(this, EventArgs.Empty);
            };
            this.LogInProxyCommand.Execute(OnAuthorized);
        }

        private void ExecuteOpenPoll(object parameter)
        {
            PollViewModel poll = parameter as PollViewModel;
            if (poll.LoadCommand.CanExecute(false)) poll.LoadCommand.Execute(false);
            this.navigationService.Navigate("PollView", poll);
        }

        private async void ExecuteRefreshUser()
        {
            if (this.serviceGateway == null)
                this.serviceGateway = new ServiceGateway<User>(this.manager);
            this.CurrentUser = await this.serviceGateway.GetModelData(OAuthConstants.URL_USER, userFileName);
            if (this.UserLoaded != null) this.UserLoaded(this, EventArgs.Empty);
        }

        private async void LoadUser()
        {
            User cachedUser = null;
            if (this.session.SessionState.ContainsKey("user"))
            {
                cachedUser = this.session.SessionState["user"] as User;
            }
            else
            {
                cachedUser = await this.serviceGateway.GetModelData(userFileName);
            }
            if (cachedUser == null)
            {
                if (this.RefreshUserCommand.CanExecute(null)) this.RefreshUserCommand.Execute(null);
            }
            else
            {
                this.CurrentUser = cachedUser;
            }
        }

        private void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            (this.LogInCommand as DelegateCommand).RaiseCanExecuteChanged();
            if (e.PropertyName == "CurrentUser" && this.CurrentUser != null)
            {
                this.session.SessionState["user"] = this.CurrentUser;
                this.Polls = new ObservableCollection<PollViewModel>();
                this.Name = this.CurrentUser.name;
                foreach (var poll in this.CurrentUser.polls)
                {
                    this.Polls.Add(new PollViewModel(poll, this.session));
                }
            }
        }
    }
}